package com.ibm.cps.model;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Throwables;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.ibm.cps.message.MessageFields;
import com.ibm.util.ErrorCode;
import com.ibm.util.JSONUtility;
import com.ibm.util.exception.CPSException;

public class ServletUtil {
	private static Logger logger = LoggerFactory.getLogger(ServletUtil.class);

	public static ByteArrayOutputStream cacheInputStream(InputStream inputStream)
			throws CPSException {
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();

			byte[] buffer = new byte[1024];
			int len;
			while ((len = inputStream.read(buffer)) > -1) {
				baos.write(buffer, 0, len);
			}
			baos.flush();
			return baos;
		} catch (Exception e) {
			throw new CPSException(ErrorCode.INTERNAL_ERROR_CODE,
					e.getMessage());
		}
	}

	public static String constructReturnMsg(int code, String message) {
		ObjectNode node = JSONUtility.newObjectNode();
		node.put(MessageFields.STATUS_CODE, code);
		node.put(MessageFields.RETURN_MESSAGE, message);
		return node.toString();
	}

	public static String constructReturnMsg(int code, ObjectNode message) {
		ObjectNode node = JSONUtility.newObjectNode();
		node.put("Code", code);
		node.set("Message", message);
		return node.toString();
	}

	public static String constructReturnMsg(int code, ArrayNode message) {
		if (message.size() == 1) {
			ObjectNode node = JSONUtility.newObjectNode();
			node.put("Code", code);
			node.set("Message", message.get(0));
			return node.toString();
		} else {
			ObjectNode node = JSONUtility.newObjectNode();
			node.put("Code", code);
			node.set("Message", message);
			return node.toString();
		}
	}

	public static String constructCollectionJson(Collection<String> metadatas)
			throws CPSException {
		JsonParser parser = new JsonParser();
		JsonArray array = new JsonArray();
		if (metadatas != null && metadatas.size() >= 1) {
			for (String ele : metadatas) {
				JsonElement node = parser.parse(ele);
				array.add(node);
			}
		}
		return constructReturnMsg(ErrorCode.SUCCESS_CODE, array);
	}

	private static String constructReturnMsg(int code, JsonElement retMsg) {
		JsonObject object = new JsonObject();
		object.addProperty("Code", code);
		object.add("Message", retMsg);
		return object.toString();
	}

	public static String getInputArguments(InputStream inputStream)
			throws CPSException {
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					inputStream));
			String input = "";
			String line;
			while ((line = reader.readLine()) != null) {
				input += line;
			}
			reader.close();
			logger.info("Request input: " + input);
			return input;
		} catch (Exception e) {
			throw new CPSException(ErrorCode.INTERNAL_ERROR_CODE,
					"Error to read input stream.");
		}
	}

	/**
	 * get parameters from request stream and formal json stream
	 * 
	 * @param req
	 * @param input
	 * @param parameters
	 * @return
	 * @throws CPSException
	 */
	public static HashMap<String, String> getParameters(HttpServletRequest req,
			String input, String... parameters) throws CPSException {
		HashMap<String, String> para2Value = new HashMap<String, String>();

		// get parameter value from request stream
		for (String para : parameters) {
			para2Value.put(para, req.getParameter(para));
		}

		if (input == null || input.length() < 1) {
			return para2Value;
		}
		// get parameter value from json stream
		ArrayNode array = JSONUtility.getArrayFromString(input);
		for (int i = 0; i < array.size(); i++) {
			JsonNode node = array.get(i);
			if (node.isObject()) {
				for (String para : parameters) {
					if (node.has(para)) {
						para2Value.put(para, node.get(para).asText());
					}
				}
			}
		}
		return para2Value;
	}

	/**
	 * get all parameters from the url
	 * @param request
	 * @return
	 */
	public static Map<String, String> getParameters(HttpServletRequest request) {
		@SuppressWarnings("unchecked")
		Map<String, String[]> parameters = request.getParameterMap();
		Map<String, String> retParas = new HashMap<String, String>();
		for (String key : parameters.keySet()) {
			retParas.put(key, request.getParameter(key));
		}
		return retParas;
	}

	public static String getException(Throwable e) {
		String retMsg;
		if (e instanceof CPSException) {
			retMsg = e.getMessage();
		} else {
			String errorMsg = Throwables.getStackTraceAsString(e);
			retMsg = ServletUtil.constructReturnMsg(
					ErrorCode.INTERNAL_ERROR_CODE, errorMsg);
		}
		return retMsg;
	}

}
